package com.xhwl.data.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xhwl.common.dto.auth.UrlPermissionDTO;
import com.xhwl.common.exception.BusinessException;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.App;
import com.xhwl.common.pojo.cent.sdata.Permission;
import com.xhwl.data.dao.IPermissionAuthDao;
import com.xhwl.data.pojo.PermissionAuth;
import com.xhwl.data.pojo.PermissionAuthDTO;
import com.xhwl.data.service.IAppService;
import com.xhwl.data.service.IPermissionAuthService;
import com.xhwl.data.service.IPermissionService;
import com.xhwl.data.util.RedisUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RequestMapping;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;


/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 10:21 2023/2/14
 */
@Service
public class PermissionAuthServiceImpl extends ServiceImpl<IPermissionAuthDao, PermissionAuth> implements IPermissionAuthService {

    @Autowired
    private IPermissionAuthDao permissionAuthDao;

    @Autowired
    private IPermissionService permissionService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private IAppService appService;

    private static final String OAUTH = "OAUTH_";

    private static final Logger log = LoggerFactory.getLogger(PermissionAuthServiceImpl.class);

    @Override
    @Transactional
    public ResultJson create(PermissionAuthDTO permissionAuthDTO) {

        List<PermissionAuth> permissionAuths = permissionAuthDTO.getPermissionAuths();
        if(CollectionUtils.isEmpty(permissionAuths)){
            return ResultJson.fail("空集合");
        }
        if(100 < permissionAuths.size()){
            return ResultJson.fail("超过数量限制");
        }
        if(null == permissionAuthDTO.getPermissionId()){
            return ResultJson.fail("缺少菜单id");
        }

        Permission permission = permissionService.getById(permissionAuthDTO.getPermissionId());
        if(null == permission){
            return ResultJson.fail("菜单不存在");
        }
        permissionAuthDTO.setCode(permission.getCode());
        QueryWrapper<PermissionAuth> permissionAuthQueryWrapper = new QueryWrapper<>();
        //permissionAuthQueryWrapper.eq("permission_id", permissionAuthDTO.getPermissionId());
        permissionAuthQueryWrapper.eq("code", permissionAuthDTO.getCode());
        Integer count = permissionAuthDao.selectCount(permissionAuthQueryWrapper);
        if(100 < count){
            return ResultJson.fail("超过数量限制, 请先删除一些");
        }

        List<PermissionAuth> updateCollect = permissionAuths.stream().filter(i -> null != i.getId()).collect(Collectors.toList());
        if(!CollectionUtils.isEmpty(updateCollect)){
            permissionAuths.removeAll(updateCollect);
            PermissionAuthDTO update = new PermissionAuthDTO();
            update.setPermissionAuths(updateCollect);
            update.setPermissionId(permissionAuthDTO.getPermissionId());
            update.setCode(permissionAuthDTO.getCode());
            update(update);
        }

        try {
            for (PermissionAuth permissionAuth : permissionAuths) {
                permissionAuth.setPermissionId(permissionAuthDTO.getPermissionId());
                permissionAuth.setServiceName(getServiceName(permissionAuth.getUrl()));
                permissionAuth.setCode(permissionAuthDTO.getCode());
            }
        }catch (Exception e){
            e.printStackTrace();
            return ResultJson.fail("url 错误");
        }

        if(CollectionUtils.isEmpty(permissionAuths)){
            log.info("传入的都是更新的数据");
            return ResultJson.success();
        }

        // 去重 保存
        this.saveBatch(distinct(permissionAuths));
        updateEveryServer(permissionAuths,permission.getAppId());
        return ResultJson.success();
    }


    public void updateEveryServer(List<PermissionAuth> permissionAuths,Integer appId){
        // 本次修改影响到授权的服务
        Map<String, List<PermissionAuth>> serviceNameMap = permissionAuths.stream().collect(Collectors.groupingBy(PermissionAuth::getServiceName, Collectors.toList()));

        // 遍历改动的每个服务
        for (Map.Entry<String, List<PermissionAuth>> stringListEntry : serviceNameMap.entrySet()) {
            try {
                saveByService(stringListEntry,appId);
            }catch (Exception e){
                e.printStackTrace();
                throw new BusinessException("创建失败 " + e.getMessage());
            }
        }
    }

    @Override
    public void refreshAppAuth(String serviceName) {
        log.info("正在刷新 {} 的授权信息", serviceName);
        // 获取当前app的菜单下面的所有授权信息
        QueryWrapper<Permission> permissionQueryWrapper = new QueryWrapper<>();
        permissionQueryWrapper.eq("app_id", serviceName);
        //permissionQueryWrapper.select("id");
        permissionQueryWrapper.select("id","code","app_id");
        List<Permission> permissions = permissionService.list(permissionQueryWrapper);
        if(org.springframework.util.CollectionUtils.isEmpty(permissions)){
            return;
        }
        //List<Integer> permissionIds = permissions.stream().map(i -> i.getId()).collect(Collectors.toList());
        List<String> codes = permissions.stream().map(i -> i.getCode()).collect(Collectors.toList());
        QueryWrapper<PermissionAuth> permissionAuthQueryWrapper = new QueryWrapper<>();
        //permissionAuthQueryWrapper.in("permission_id", permissionIds);
        permissionAuthQueryWrapper.in("code", codes);
        List<PermissionAuth> list = this.list(permissionAuthQueryWrapper);
        if(org.springframework.util.CollectionUtils.isEmpty(list)){
            return;
        }
        this.updateEveryServer(list,permissions.get(0).getAppId());
    }

    /**
     * 去重（permission+url 唯一）
     * @param sources
     * @return
     */
    private List<PermissionAuth> distinct(List<PermissionAuth> sources){
        if(CollectionUtils.isEmpty(sources)){
            return sources;
        }
        List<PermissionAuth> permissionAuths = distinctSource(sources);
        //List<Integer> permissionIds = permissionAuths.stream().map(i -> i.getPermissionId()).collect(Collectors.toList());
        List<String> codes = permissionAuths.stream().map(i -> i.getCode()).collect(Collectors.toList());
        QueryWrapper<PermissionAuth> permissionAuthQueryWrapper11 = new QueryWrapper<>();
        //permissionAuthQueryWrapper11.in("permission_id", permissionIds.stream().distinct().collect(Collectors.toList()));
        permissionAuthQueryWrapper11.in("code", codes.stream().distinct().collect(Collectors.toList()));
        List<PermissionAuth> list1 = this.list(permissionAuthQueryWrapper11);
        Map<String, List<PermissionAuth>> permissionAuthMap = list1.stream().collect(Collectors.groupingBy(PermissionAuth::getCode));
        List<PermissionAuth> distinctPermissionAuths = permissionAuths.stream().filter(i -> {
            List<PermissionAuth> permissionAuths1 = permissionAuthMap.get(i.getCode());
            if(CollectionUtils.isEmpty(permissionAuths1)){
                return true;
            }else{
                List<String> collect = permissionAuths1.stream().map(j -> j.getUrl()).collect(Collectors.toList());
                return !collect.contains(i.getUrl());
            }
        }).collect(Collectors.toList());
        return distinctPermissionAuths;
    }

    /**
     * 根据 permissionid 和 servicename 去重
     * @param permissionAuths
     * @return
     */
    private List<PermissionAuth> distinctSource(List<PermissionAuth> permissionAuths){
        if(CollectionUtils.isEmpty(permissionAuths)){
            return permissionAuths;
        }
        List<PermissionAuth> resultList = new ArrayList<>();
        Set<String> uniqueSet = new HashSet<>();
        for (PermissionAuth permissionAuth : permissionAuths) {
            //String uniqueKey = permissionAuth.getPermissionId() + permissionAuth.getServiceName() + permissionAuth.getUrl();
            String uniqueKey = permissionAuth.getCode() + permissionAuth.getServiceName() + permissionAuth.getUrl();
            if(!uniqueSet.contains(uniqueKey)){
                resultList.add(permissionAuth);
                uniqueSet.add(uniqueKey);
            }
        }
        return resultList;
    }

    @Override
    @Transactional
    public ResultJson update(PermissionAuthDTO permissionAuthDTO) {

        /*if(null == permissionAuthDTO.getPermissionId()){
            return ResultJson.fail("缺少permission id");
        }*/

        if(null == permissionAuthDTO.getCode()){
            return ResultJson.fail("缺少code");
        }

        if(CollectionUtils.isEmpty(permissionAuthDTO.getPermissionAuths())){
            return ResultJson.success();
        }

        Permission permission = permissionService.getById(permissionAuthDTO.getPermissionId());
        if(null == permission){
            return ResultJson.fail("permission 不存在");
        }

        List<PermissionAuth> permissionAuthsNew = permissionAuthDTO.getPermissionAuths().stream().filter(i -> null != i.getId()).collect(Collectors.toList());
        List<Integer> permissionAuthIds = permissionAuthsNew.stream().map(i -> i.getId()).collect(Collectors.toList());
        if(CollectionUtils.isEmpty(permissionAuthIds)){
            log.info("id is empty");
            return ResultJson.success();
        }
        //设置code值
        for(PermissionAuth vo : permissionAuthsNew){
            vo.setCode(permissionAuthDTO.getCode());
        }
        Map<Integer, PermissionAuth> newMap = permissionAuthsNew.stream().collect(Collectors.toMap(PermissionAuth::getId, Function.identity()));


        List<PermissionAuth> permissionAuthsOld = listByIds(permissionAuthIds);
        if(CollectionUtils.isEmpty(permissionAuthsOld)){
            log.info("查询结果为空");
            return ResultJson.success();
        }

        deleteForOld(permissionAuthsOld, permission);

        List<PermissionAuth> distinct = distinct(permissionAuthsNew);
        if(CollectionUtils.isEmpty(distinct)){
            log.info("去重后为空");
            return ResultJson.success();
        }
        // 填充service name
        distinct.stream().forEach(i -> i.setServiceName(getServiceName(i.getUrl())));

        // 填充新值
        for (PermissionAuth permissionAuth : permissionAuthsOld) {
            permissionAuth.setUrl(newMap.get(permissionAuth.getId()).getUrl());
            permissionAuth.setDescription(newMap.get(permissionAuth.getId()).getDescription());
        }

        this.updateBatchById(distinct);

        // 更新redis 里的数据
        permissionAuthsOld.stream().forEach(i -> i.setId(null));
        PermissionAuthDTO permissionAuthDTO1 = new PermissionAuthDTO();
        permissionAuthDTO1.setPermissionAuths(permissionAuthsOld);
        permissionAuthDTO1.setPermissionId(permission.getId());
        permissionAuthDTO1.setCode(permission.getCode());
        create(permissionAuthDTO1);

        return ResultJson.success();
    }

    /**
     * 处理redis中的旧值
     * @param distinct
     * @param permission
     */
    private void deleteForOld(List<PermissionAuth> distinct, Permission permission){
        // 删除redis中旧的值
        for (PermissionAuth p : distinct) {

            Object o = redisUtils.hmGet(OAUTH + p.getServiceName(), getRealUrl(p.getUrl()));
            if(null == o){
                continue;
            }
            UrlPermissionDTO urlPermissionDTOSOld = JSONObject.parseObject(JSONObject.toJSONString(o), new TypeReference<UrlPermissionDTO>() {
            });
            List<String> collect = Arrays.asList(urlPermissionDTOSOld.getCode().split(","));
            if(1 == collect.size() && collect.contains(permission.getCode())){
                redisTemplate.opsForHash().delete(OAUTH + p.getServiceName(), getRealUrl(p.getUrl()));
            }else if(collect.contains(permission.getCode())){
                collect = collect.stream().filter(i-> !i.equals(permission.getCode())).collect(Collectors.toList());
                // 更新
                redisUtils.hmSet(OAUTH + p.getServiceName(), getRealUrl(p.getUrl()), dataMapHandler(collect));
            }
        }
    }

    /**
     * 遍历服务名保存授权信息
     * @param stringListEntry
     */
    private void saveByService(Map.Entry<String, List<PermissionAuth>> stringListEntry,Integer appId){
        String serviceName = stringListEntry.getKey();

        if(StringUtils.isEmpty(serviceName)){
            throw new DataException("服务名错误");
        }

        List<PermissionAuth> value = stringListEntry.getValue();

        List<String> collect = value.stream().map(i -> i.getUrl()).collect(Collectors.toList());

        //Integer currPId = value.get(0).getPermissionId();

        // 当前操作的app
        //Permission p = permissionService.getById(currPId);
        App app = appService.getAppById(appId);

        // 获取当前app下所有的菜单
        QueryWrapper<Permission> permissionQueryWrapper = new QueryWrapper<>();
        permissionQueryWrapper.select("id", "code");
        permissionQueryWrapper.eq("app_id", app.getId());
        List<Permission> list = permissionService.list(permissionQueryWrapper);

        //Map<Integer, String> idCodeMap = list.stream().collect(Collectors.toMap(Permission::getId, Permission::getCode));

        // 查询当前包含这个接口url的配置
        QueryWrapper<PermissionAuth> permissionAuthQueryWrapper1 = new QueryWrapper<>();
        permissionAuthQueryWrapper1.in("url", collect);
        permissionAuthQueryWrapper1.in("service_name", serviceName);
        //permissionAuthQueryWrapper1.in("permission_id", list.stream().map(i -> i.getId()).collect(Collectors.toList()));
        permissionAuthQueryWrapper1.in("code", list.stream().map(i -> i.getCode()).collect(Collectors.toList()));
        List<PermissionAuth> permissionAuths1 = permissionAuthDao.selectList(permissionAuthQueryWrapper1);
        Map<String, List<PermissionAuth>> urlMap = permissionAuths1.stream().collect(Collectors.groupingBy(PermissionAuth::getUrl, Collectors.toList()));

        String key = OAUTH+serviceName+"_"+ app.getAppId();
        for (PermissionAuth permissionAuth : value) {
            List<PermissionAuth> permissionAuths2 = urlMap.get(permissionAuth.getUrl());
            //List<String> codes = permissionAuths2.stream().map(i -> idCodeMap.get(i.getPermissionId())).distinct().collect(Collectors.toList());
            if(CollectionUtil.isNotEmpty(permissionAuths2)) {
                List<String> codes = permissionAuths2.stream().map(i -> i.getCode()).distinct().collect(Collectors.toList());
                redisUtils.hmSet(key, getRealUrl(permissionAuth.getUrl()), dataMapHandler(codes));
            }
        }
    }

    @Override
    @Transactional
    public ResultJson delete(Integer id) {

        if(null == id){
            return ResultJson.fail("参数错误");
        }
        PermissionAuth p = this.getById(id);
        if(null == p){
            return ResultJson.fail("不存在");
        }
        this.removeById(id);

        // 更新redis
        redisTemplate.opsForHash().delete(OAUTH + p.getServiceName(), getRealUrl(p.getUrl()));
        QueryWrapper<PermissionAuth> permissionAuthQueryWrapper = new QueryWrapper<>();
        permissionAuthQueryWrapper.eq("service_name", p.getServiceName());
        permissionAuthQueryWrapper.eq("url", p.getUrl());
        List<PermissionAuth> list = this.list(permissionAuthQueryWrapper);
        if(!list.isEmpty()){
            //List<Integer> collect = list.stream().map(i -> i.getPermissionId()).collect(Collectors.toList());
            List<String> collect = list.stream().map(i -> i.getCode()).collect(Collectors.toList());
            QueryWrapper<Permission> queryWrapper = new QueryWrapper<>();
            queryWrapper.in("code",collect);
            List<Permission> permissions = permissionService.list(queryWrapper);
            List<String> codes = permissions.stream().map(i -> i.getCode()).distinct().collect(Collectors.toList());

            redisUtils.hmSet(OAUTH + p.getServiceName(), getRealUrl(p.getUrl()), dataMapHandler(codes));
        }
        return ResultJson.success();
    }

    @Override
    public ResultJson delete(List<Integer> id) {
        if(CollectionUtils.isEmpty(id)){
            return ResultJson.success();
        }
        for (Integer integer : id) {
            delete(integer);
        }
        return ResultJson.success();
    }


    /**
     * 转换成redis里面的对象值
     * @param codes
     * @return
     */
    private static UrlPermissionDTO dataMapHandler(List<String> codes){
        UrlPermissionDTO urlPermissionDTO = new UrlPermissionDTO();
        urlPermissionDTO.setCode(String.join(",", codes));
        urlPermissionDTO.setType("OR");
        return urlPermissionDTO;
    }


    /**
     * 从url中获取服务名
     * @param str
     * @return
     */
    private static String getServiceName(String str){
        return str.split("/")[1];
    }

    /**
     * 从url中获取真实的接口请求路径（排除服务名的）
     * @param str
     * @return
     */
    private static String getRealUrl(String str){
        return str.substring(str.indexOf("/", 1));
    }

}
